﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace pipeCore.Pipes.Units.NamedPortUnits.Units
{
    /// <summary>
    /// This is the Base Filter interface that all filters are derived from, A filter is a unit that have more than one input and more than one output
    /// this unit is a combination of s ink source and a sink source
    /// </summary>
    public interface IFilter : ISinkunit,ISourceunit
    {
       
    }
    /// <summary>
    /// this class represent a filter
    /// </summary>
    public abstract class  FilterBase : IFilter
    {

        /// <summary>
        /// Run all the ports to listing for request
        /// </summary>
        public void Run()
        {
            try
            {
                string[] portname = PortsIn.Keys.ToArray();
                for (int i = 0; i < PortsIn.Keys.Count; i++) ((pipeCore.Pipes.Ports.Iinport)(PortsIn[portname[i]])).Listen();
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
            }
        }
        /// <summary>
        /// trigerd when message is recived 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public abstract void OnMessageRecived(object sender, Ports.OnMessageRecivedEventArg e);
        /// <summary>
        /// Collection of input ports
        /// </summary>
        public Dictionary<string, Ports.Iinport> PortsIn
        {
            get;
            set;
        }
        /// <summary>
        /// The Unit NAme
        /// </summary>
        public string UnitName
        {
            
            get;
            set;
        }
        /// <summary>
        /// Add a new port to the Unit,inherited from IUnit
        /// </summary>
        /// <param name="port"></param>
        public void Add(Ports.IPort port)
        {
            try
            {
                if (port is pipeCore.Pipes.Ports.Iinport)
                {
                    PortsIn.Add("portnin_" + PortsIn.Count.ToString(), (pipeCore.Pipes.Ports.Iinport)port);
                    ((pipeCore.Pipes.Ports.Iinport)port).OnMessageRecive += new EventHandler<Ports.OnMessageRecivedEventArg>(OnMessageRecived);
                }
                else
                {
                    PortsOut.Add("portnout_" + PortsIn.Count.ToString(), (pipeCore.Pipes.Ports.Ioutport)port);
                }
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
            }


        }
        /// <summary>
        /// Add a new Port
        /// </summary>
        /// <param name="port">the port object to add</param>
        /// <param name="Name">the name of the port</param>
        public void Add(Ports.IPort port, string Name)
        {
            try
            {
                if (port is pipeCore.Pipes.Ports.Iinport)
                {
                    PortsIn.Add(Name, (pipeCore.Pipes.Ports.Iinport)port);
                    ((pipeCore.Pipes.Ports.Iinport)port).OnMessageRecive += new EventHandler<Ports.OnMessageRecivedEventArg>(OnMessageRecived);
                }
                else
                {
                    PortsOut.Add("portnout_" + Name, (pipeCore.Pipes.Ports.Ioutport)port);
                }
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
            }
        }
        /// <summary>
        /// Add a new port, the nameing will effect the type of port to be added if it contain in_, it is an input,otherwise an output
        /// </summary>
        /// <param name="Name"></param>
        public void Add(string Name)
        {
            try
            {
                if (Name.Contains("in_"))
                {
                    pipeCore.Pipes.Units.NamedPortUnits.ports.Inport port = new ports.Inport(Name);
                    Add(port, Name);
                }
                else
                {
                    pipeCore.Pipes.Units.NamedPortUnits.ports.Outport port = new ports.Outport(Name);
                    Add(port, Name);
                }
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
            }
            
        }

        /// <summary>
        /// Add a new inport to the unit
        /// </summary>
        /// <param name="Name">port name</param>
        public void AddInputPort(String Name)
        {
            try
            {
                pipeCore.Pipes.Units.NamedPortUnits.ports.Inport port = new pipeCore.Pipes.Units.NamedPortUnits.ports.Inport(Name);
                PortsIn.Add(Name, (pipeCore.Pipes.Ports.Iinport)port);
                port.Name = Name;
                ((pipeCore.Pipes.Ports.Iinport)port).OnMessageRecive += new EventHandler<Ports.OnMessageRecivedEventArg>(OnMessageRecived);
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
               
            }
        }
        /// <summary>
        /// Add a new OutputPort
        /// </summary>
        /// <param name="Name">port name</param>
        public void AddOutputPort(String Name)
        {
            pipeCore.Pipes.Units.NamedPortUnits.ports.Outport port = new pipeCore.Pipes.Units.NamedPortUnits.ports.Outport(Name);
            PortsOut.Add(Name, port);
            port.Name = Name;
        }


        /// <summary>
        /// Trigger all the outport to send 
        /// </summary>
       
        public void Send()
        {
            string[] portname = PortsOut.Keys.ToArray();
            for (int i = 0; i < PortsOut.Keys.Count; i++) ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portname[i]])).Send();
        }
        /// <summary>
        /// trigger the specified ports to send there data
        /// </summary>
        /// <param name="ports"></param>
        public void Send(String[] ports)
        {
            for (int i = 0; i < ports.Length; i++) ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[ports[i]])).Send();
        }
        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="portName"></param>
        public void Send(String portName)
        {
            ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portName])).Send();
        }

        /// <summary>
        /// Collection of Output ports
        /// </summary>
        public Dictionary<string, Ports.IPort> PortsOut
        {
            get;
            set;
        }

        /// <summary>
        /// Connect a specific port to an other
        /// </summary>
        /// <param name="pinSource">from pin</param>
        /// <param name="PinSink">to pin </param>
        public void Connect(string pinSource, string PinSink)
        {
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[pinSource]).Connect(PinSink);
        }

        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="p">the port to use </param>
        /// <param name="p_2">a message string</param>
        public void SendFrom(string p, string p_2)
        {
            byte[] msg = System.Text.ASCIIEncoding.ASCII.GetBytes(p_2);
            SendFrom(p, msg);
        }

        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="portname">the port name</param>
        /// <param name="message">a byte arry of message</param>
        public void SendFrom(string portname, byte[] message)
        {
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[portname]).Data = message;
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[portname]).Send();
        }
        ISite site;
        /// <summary>
        /// Inherited from IComponent
        /// </summary>
        public event EventHandler Disposed;
        /// <summary>
        /// Inherited from IComponent
        /// </summary>
        public System.ComponentModel.ISite Site
        {
            get
            {
                return site;
            }
            set
            {
                site=value;
            }
        }
        /// <summary>
        /// Inherited from IComponent
        /// </summary>
        public void Dispose()
        {
            string[] portname = PortsIn.Keys.ToArray();
            for (int i = 0; i < PortsIn.Keys.Count; i++) ((pipeCore.Pipes.Ports.Iinport)(PortsIn[portname[i]])).Dispose();

           portname = PortsOut.Keys.ToArray();
            for (int i = 0; i < PortsIn.Keys.Count; i++)
                ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portname[i]])).Dispose();
           
        }

        /// <summary>
        /// Create a new Unit
        /// </summary>
        public abstract void Create();

    }
}
